home *** CD-ROM | disk | FTP | other *** search
- /* TNC-2 emulator for use by RLI or MBL bbs (or other programs) */
-
- #include <ctype.h>
- #include <time.h>
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "timer.h"
- #include "ax25.h"
- #include "lapb.h"
- #include "kiss.h"
- #include "slip.h"
- #include "tnc2.h"
-
- #undef ALLCMDS 1 /* include unsupported cmds? */
- #define BEACON 1 /* include BEACON possibility? */
-
- struct tnc *tnc2s = NULLTNC; /* TNC controlblocks */
- static void tnc2_recv(); /* upcall handlers */
-
- /* TNC commands supported by the emulator */
- static void dotnconmode(),dotnconnect(),dotnconverse(),
- dotncstatus(),dotndaytime(),dotndiscon(),dotndisplay(),
- dotnmycall(),dotnrestart(),dotntrans(),dotnunproto();
-
- void dotnmheard(),dotnreset();
-
- static struct tnccommand tnccommands[] =
- {
- "8BITCONV", TC_ON_OFF, 0, NULLVFP,
- #ifdef ALLCMDS
- "AX25L2V2", TC_ON_OFF, 1, NULLVFP, /* not used */
- #endif
- "AUTOLF", TC_ON_OFF, 2, NULLVFP,
- #ifdef ALLCMDS
- "AWLEN", TC_DECVAL, 3, NULLVFP, /* not used */
- "AXDELAY", TC_DECVAL, 4, NULLVFP, /* not used */
- "AXHANG", TC_DECVAL, 5, NULLVFP, /* not used */
- #endif
- #if (defined(BEACON) || defined(ALLCMDS))
- "BEACON", TC_TIMER, 0, (void (*)()) 10000,
- #endif
- "BBSMSGS", TC_ON_OFF, 55, NULLVFP,
- "BKONDEL", TC_ON_OFF, 6, NULLVFP,
- #if (defined(BEACON) || defined(ALLCMDS))
- "BTEXT", TC_TEXT, 0, NULLVFP,
- #endif
- #ifdef ALLCMDS
- "BUDLIST", TC_ON_OFF, 7, NULLVFP, /* not used */
- #endif
- "CONNECT", TC_EXEC, 0, dotnconnect,
- "CBELL", TC_ON_OFF, 8, NULLVFP,
- #ifdef ALLCMDS
- "CONPERM", TC_ON_OFF, 9, NULLVFP, /* not used */
- "CHECK", TC_DECVAL, 10, NULLVFP, /* not used */
- "CLKADJ", TC_DECVAL, 11, NULLVFP, /* not used */
- #endif
- "CMDTIME", TC_DECVAL, 12, NULLVFP,
- "CMSG", TC_ON_OFF, 13, NULLVFP,
- "CMSGDISC", TC_ON_OFF, 14, NULLVFP,
- "CPACTIME", TC_ON_OFF, 15, NULLVFP,
- "CR", TC_ON_OFF, 16, NULLVFP,
- "CSTATUS", TC_EXEC, 0, dotncstatus,
- "CTEXT", TC_TEXT, 1, NULLVFP,
- "CANLINE", TC_HEXVAL, 17, NULLVFP,
- "COMMAND", TC_HEXVAL, 18, NULLVFP,
- #ifdef ALLCMDS
- "CALSET", TC_DECVAL, 19, NULLVFP, /* not used */
- #endif
- "CANPAC", TC_HEXVAL, 20, NULLVFP,
- "CONOK", TC_ON_OFF, 21, NULLVFP,
- "CONMODE", TC_MISC, 0, dotnconmode,
- "CONSTAMP", TC_ON_OFF, 22, NULLVFP,
- "CONVERSE", TC_EXEC, 0, dotnconverse,
- "DISCONNE", TC_EXEC, 0, dotndiscon,
- "DAYTIME", TC_EXEC, 0, dotndaytime,
- "DAYUSA", TC_ON_OFF, 23, NULLVFP,
- "DELETE", TC_ON_OFF, 24, NULLVFP,
- #ifdef ALLCMDS
- "DWAIT", TC_DECVAL, 25, NULLVFP, /* not used */
- "DIGIPEAT", TC_ON_OFF, 26, NULLVFP, /* not used */
- #endif
- "DISPLAY", TC_EXEC, 0, dotndisplay,
- "ECHO", TC_ON_OFF, 27, NULLVFP,
- #ifdef ALLCMDS
- "ESCAPE", TC_ON_OFF, 28, NULLVFP, /* not used */
- #endif
- "FLOW", TC_ON_OFF, 29, NULLVFP,
- #ifdef ALLCMDS
- "FRACK", TC_DECVAL, 30, NULLVFP, /* not used */
- "FULLDUP", TC_ON_OFF, 31, NULLVFP, /* not used */
- "HEADERLN", TC_ON_OFF, 32, NULLVFP, /* not used */
- "HEALLED", TC_ON_OFF, 33, NULLVFP, /* not used */
- "HID", TC_ON_OFF, 34, NULLVFP, /* not used */
- "ID", TC_EXEC, 0, NULLVFP,
- #endif
- "K", TC_EXEC, 0, dotnconverse, /* ALIAS for CONVERSE */
- "KISS", TC_ON_OFF, 76, NULLVFP,
- "KISSRX", TC_DECVAL, 77, NULLVFP,
- #ifdef ALLCMDS
- "LCOK", TC_ON_OFF, 35, NULLVFP, /* not used */
- #endif
- "LFADD", TC_ON_OFF, 36, NULLVFP,
- "LFIGNORE", TC_ON_OFF, 37, NULLVFP,
- #ifdef ALLCMDS
- "LCALLS", TC_TEXT, 2, NULLVFP, /* not used */
- "LCSTREAM", TC_ON_OFF, 38, NULLVFP, /* not used */
- #endif
- "MONITOR", TC_ON_OFF, 39, NULLVFP, /* not used, incl for BBS */
- #ifdef ALLCMDS
- "MALL", TC_ON_OFF, 40, NULLVFP, /* not used */
- "MCON", TC_ON_OFF, 41, NULLVFP, /* not used */
- "MFILTER", TC_MISC, 1, NULLVFP, /* not used */
- #endif
- "MHEARD", TC_EXEC, 0, dotnmheard,
- #ifdef ALLCMDS
- "MHCLEAR", TC_EXEC, 0, NULLVFP,
- "MRPT", TC_ON_OFF, 42, NULLVFP, /* not used */
- "MSTAMP", TC_ON_OFF, 43, NULLVFP, /* not used */
- #endif
- "MYCALL", TC_EXEC, 0, dotnmycall,
- #ifdef ALLCMDS
- "MYALIAS", TC_TEXT, 3, NULLVFP, /* not used */
- "MAXFRAME", TC_DECVAL, 44, NULLVFP, /* not used */
- "MCOM", TC_ON_OFF, 45, NULLVFP, /* not used */
- #endif
- "NEWMODE", TC_ON_OFF, 46, NULLVFP,
- "NOMODE", TC_ON_OFF, 47, NULLVFP,
- #ifdef ALLCMDS
- "NUCR", TC_ON_OFF, 48, NULLVFP, /* not used */
- "NULF", TC_ON_OFF, 49, NULLVFP, /* not used */
- "NULLS", TC_DECVAL, 50, NULLVFP, /* not used */
- #endif
- "PACLEN", TC_DECVAL, 51, NULLVFP,
- #ifdef ALLCMDS
- "PARITY", TC_DECVAL, 52, NULLVFP, /* not used */
- #endif
- "PASS", TC_HEXVAL, 53, NULLVFP,
- #ifdef ALLCMDS
- "PASSALL", TC_ON_OFF, 54, NULLVFP, /* not used */
- #endif
- "PACTIME", TC_TIMER, 1, (void (*)()) 100,
- #ifdef ALLCMDS
- "RETRY", TC_DECVAL, 56, NULLVFP, /* not used */
- #endif
- "REDISPLA", TC_HEXVAL, 57, NULLVFP,
- #ifdef ALLCMDS
- "RECONNEC", TC_EXEC, 0, NULLVFP,
- "RESPTIME", TC_DECVAL, 58, NULLVFP, /* not used */
- #endif
- "RESTART", TC_EXEC, 0, dotnrestart,
- "RESET", TC_EXEC, 0, dotnreset,
- "RXBLOCK", TC_ON_OFF, 59, NULLVFP,
- #ifdef ALLCMDS
- "SCREENLN", TC_DECVAL, 60, NULLVFP, /* not used */
- #endif
- "SENDPAC", TC_HEXVAL, 61, NULLVFP,
- "START", TC_HEXVAL, 62, NULLVFP,
- "STOP", TC_HEXVAL, 63, NULLVFP,
- #ifdef ALLCMDS
- "STREAMSW", TC_HEXVAL, 64, NULLVFP, /* not used */
- "STREAMCA", TC_ON_OFF, 65, NULLVFP, /* not used */
- "STREAMDB", TC_ON_OFF, 66, NULLVFP, /* not used */
- #endif
- "TRANS", TC_EXEC, 0, dotntrans,
- #ifdef ALLCMDS
- "TRIES", TC_EXEC, 0, NULLVFP, /* not used */
- #endif
- "TRFLOW", TC_ON_OFF, 67, NULLVFP,
- #ifdef ALLCMDS
- "TRACE", TC_ON_OFF, 68, NULLVFP, /* not used */
- "TXDELAY", TC_DECVAL, 69, NULLVFP, /* not used */
- #endif
- "TXFLOW", TC_ON_OFF, 70, NULLVFP,
- "TXUIFRAM", TC_ON_OFF, 78, NULLVFP,
- "UNPROTO", TC_EXEC, 0, dotnunproto,
- #ifdef ALLCMDS
- "USERS", TC_DECVAL, 71, NULLVFP, /* not used */
- #endif
- "XFLOW", TC_ON_OFF, 72, NULLVFP,
- #ifdef ALLCMDS
- "XMITOK", TC_ON_OFF, 73, NULLVFP, /* not used */
- #endif
- "XOFF", TC_HEXVAL, 74, NULLVFP,
- "XON", TC_HEXVAL, 75, NULLVFP,
- "", 0, 0, NULLVFP
- };
-
- static char def_params[] = {
- 0, 1, 1, 7, 0, 0, 1, 0, 0, 0, 30, 0, 1, 0, 0, 0,
- 1, 0x18, 0x03, 0, 0x19, /*1*/ 0, 0, 1, 0, 16, 1, 1, 0, 1, 3, 0,
- 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 2, 1, 0, 0,
- 0, 0, 0, 128, 3, 0x16, 0, 0, 10, 0x12, 0, 0, 80, 0x0d, 0x11, 0x13,
- 0x7c, 0, 0, 0, 0, 30, 0, 1, 1, 1, 0x13, 0x11, 0, 1, 0
- };
-
- char tnc2_prompt[] = "cmd:";
- static char tnc2_bad[] = "?bad\r";
- static char tnc2_call[] = "?call\r";
- static char tnc2_notenough[] = "?not enough\r";
- static char tnc2_toomany[] = "?too many\r";
- static char tnc2_was[] = "was ";
- static char tnc2_conrq[] = "*** connect request:";
- static char tnc2_bslcr[] = "\\\r";
- static char tnc2_cr[] = "\r";
- extern char *ax25mesgs[];
-
- /* send message to client (BBS) */
- void
- tnc2_mesg (tnc2,s)
- register struct tnc *tnc2;
- register unsigned char *s;
-
- {
- while (*s) {
- if (!tnc2_ochar(tnc2,*s))
- break;
-
- if (*s++ == '\r' && tnc2->param[2]) /* AUTOLF */
- if (!tnc2_ochar(tnc2,'\n'))
- break;
- }
- }
-
- /* process character input in cooked mode, return 1 if line complete */
- int
- tnc2_line (tnc2,c)
- register struct tnc *tnc2;
- register char c;
-
- {
- if (tnc2->passc) { /* prev was PASS char? */
- tnc2->passc = 0; /* clear the flag */
- tnc2->linebuf[tnc2->linepos++] = c; /* store the passed char */
- tnc2->linebuf[tnc2->linepos] = '\0';
-
- if (tnc2->param[27]) /* ECHO ON */
- tnc2_mesg(tnc2,tnc2->linebuf + tnc2->linepos - 1); /* echo it */
-
- goto checkbuf;
- }
-
- if (tnc2->param[17] && c == tnc2->param[17]) { /* CANLINE character */
- while (tnc2->linepos > 0)
- if (tnc2->linebuf[--(tnc2->linepos)] == '\r') {/* up to CR */
- tnc2->linepos++;
- break;
- }
-
- tnc2_mesg(tnc2,tnc2_bslcr);
- return TL_CANCEL;
- }
-
- if (tnc2->param[18] && c == tnc2->param[18]) /* COMMAND character */
- return TL_COMMAND;
-
- if (tnc2->param[20] && c == tnc2->param[20]) { /* CANPAC character */
- tnc2->linepos = 0; /* clear entire line (packet) */
- tnc2_mesg(tnc2,tnc2_bslcr);
- return TL_CANCEL;
- }
-
- if ((tnc2->param[24] && c == 0x7f) || /* DELETE ON, DEL */
- (!tnc2->param[24] && c == '\b')) { /* DELETE OFF, BS */
- if (tnc2->linepos > 0) {
- tnc2->linepos--;
- if (tnc2->param[27]) /* ECHO ON */
- tnc2_mesg(tnc2,tnc2->param[6]? /* BKONDEL */
- "\b \b" : "\\");
- }
- return TL_INCOMPLETE;
- }
-
- if (tnc2->param[37] && c == '\n') /* LFIGNORE */
- return TL_INCOMPLETE;
-
- if (tnc2->param[53] && c == tnc2->param[53]) { /* PASS character */
- tnc2->passc = 1; /* set a flag */
- return TL_INCOMPLETE;
- }
-
- if (tnc2->param[57] && c == tnc2->param[57]) { /* REDISPLAY character */
- tnc2_mesg(tnc2,tnc2_bslcr);
-
- if (tnc2->mode == TM_CMD) /* dirty, but... */
- tnc2_mesg(tnc2,tnc2_prompt);
-
- tnc2->linebuf[tnc2->linepos] = '\0';
- tnc2_mesg(tnc2,tnc2->linebuf);
-
- return TL_INCOMPLETE;
- }
-
- if (tnc2->mode != TM_CMD && c == tnc2->param[61]) { /* SENDPAC character */
- if (tnc2->param[16]) /* CR ON? */
- tnc2->linebuf[tnc2->linepos++] = c;
-
- if (tnc2->param[36] && c == '\r') /* LFADD */
- tnc2->linebuf[tnc2->linepos++] = '\n';
-
- tnc2->linebuf[tnc2->linepos] = '\0';
-
- if (tnc2->param[27] && tnc2->param[16]) /* ECHO ON, CR ON? */
- tnc2_mesg(tnc2,tnc2->linebuf + tnc2->linepos - 1);
-
- return TL_PACKET;
- }
-
- if ((tnc2->param[62] && c == tnc2->param[62]) || /* START */
- (tnc2->param[63] && c == tnc2->param[63])) /* STOP */
- return TL_INCOMPLETE; /* ignore them */
-
- tnc2->linebuf[tnc2->linepos++] = c; /* store it */
- tnc2->linebuf[tnc2->linepos] = '\0';
-
- if (tnc2->param[27]) /* ECHO ON */
- tnc2_mesg(tnc2,tnc2->linebuf + tnc2->linepos - 1); /* echo it */
-
- if (c == '\r') { /* CR is end of line */
- if (tnc2->mode == TM_CMD)
- return TL_COMPLETE;
- else
- if (tnc2->param[36]) /* LFADD */
- tnc2->linebuf[tnc2->linepos++] = '\n';
- }
-
- checkbuf:
- if (tnc2->linepos >= sizeof(tnc2->linebuf) - 3) /* buffer full */
- return TL_COMPLETE;
-
- return TL_INCOMPLETE; /* await more characters */
- }
-
- /* get a word from the command line and convert to uppercase */
- static char *
- getword (cpp)
- register char **cpp;
-
- {
- register char c;
- char *rv;
-
- if (*cpp == NULLCHAR) /* already at end? */
- return NULLCHAR;
-
- while ((c = **cpp) == ' ' || c == '\t') /* skip leading whitespace */
- (*cpp)++;
-
- if (c == '\0' || c == '\r') /* now at end of line? */
- return NULLCHAR;
-
- rv = *cpp;
-
- while ((c = **cpp) != '\0' && c != '\r' && /* collect it */
- c != ' ' && c != '\t' && c != ',') {
- if (islower(c))
- **cpp = toupper(c);
-
- (*cpp)++;
- }
-
- *(*cpp)++ = '\0'; /* terminate word */
-
- if (c == '\0' || c == '\r') /* now at end? */
- *cpp = NULLCHAR;
- else
- if (c == ',') /* skip comma */
- (*cpp)++;
-
- return rv;
- }
-
- /* return date and time in a string */
- char *
- tnc2_daytime (tnc2,tloc)
- struct tnc *tnc2;
- time_t tloc;
-
- {
- static char dt_string[20]; /* static area for result */
- struct tm *ltime;
-
- ltime = localtime(&tloc); /* convert time to tm_t */
-
- if (tnc2->param[23]) /* DAYUSA */
- sprintf(dt_string,"%02d/%02d/%02d %02d:%02d:%02d",
- ltime->tm_mon + 1,ltime->tm_mday,ltime->tm_year,
- ltime->tm_hour,ltime->tm_min,ltime->tm_sec);
- else
- sprintf(dt_string,"%02d-%02d-%02d %02d:%02d:%02d",
- ltime->tm_mday,ltime->tm_mon + 1,ltime->tm_year,
- ltime->tm_hour,ltime->tm_min,ltime->tm_sec);
-
- return dt_string;
- }
-
- /* show parameter value, with optional "was" */
- static void
- showparm (tnc2,tcmd,was)
- register struct tnc *tnc2;
- struct tnccommand *tcmd;
- char was;
-
- {
- char buf[40],*p;
-
- sprintf(buf,"%-9s%s",tcmd->name,was? tnc2_was : "");
- p = buf + strlen(buf);
-
- switch (tcmd->type)
- {
- case TC_ON_OFF:
- strcpy(p,tnc2->param[tcmd->paramnum]? "ON" : "OFF");
- break;
-
- case TC_DECVAL:
- sprintf(p,"%d",uchar(tnc2->param[tcmd->paramnum]));
- break;
-
- case TC_HEXVAL:
- sprintf(p,"$%02x",uchar(tnc2->param[tcmd->paramnum]));
- while (*++p)
- if (islower(*p))
- *p = toupper(*p);
- break;
-
- case TC_TEXT:
- tnc2_mesg(tnc2,buf);
- tnc2_mesg(tnc2,(tnc2->text[tcmd->paramnum] != NULLCHAR)?
- tnc2->text[tcmd->paramnum] : tnc2_cr);
- return;
-
- case TC_TIMER:
- sprintf(p,"%s %d",tnc2->every[tcmd->paramnum]? "EVERY" : "AFTER",
- (int) (TICK2MS(tnc2->timer[tcmd->paramnum].start) / (long) tcmd->func));
- break;
-
- case TC_MISC:
- switch (tcmd->paramnum)
- {
- case 0: /* CONMODE */
- strcat(p,(tnc2->conmode == TM_CONV)? "CONVERSE" : "TRANS");
- break;
-
- case 1: /* MFILTER */
- break;
- }
- }
-
- strcat(p,tnc2_cr);
- tnc2_mesg(tnc2,buf);
- }
-
- /* execute command in the linebuffer */
- static void
- tnc2_exec (tnc2)
- register struct tnc *tnc2;
-
- {
- register char *word;
- register struct tnccommand *tcmd = tnccommands;
- char *p = tnc2->linebuf;
- register int paramnum;
- int len,v;
-
- if ((word = getword(&p)) == NULLCHAR) /* get keyword */
- return; /* empty line, ignore it */
-
- if ((len = strlen(word)) == 0) /* take keyword len */
- goto eh; /* garbage, print ?EH */
-
- while (tcmd->name[0] != '\0') { /* check the command names */
- if (!strncmp(tcmd->name,word,len)) {
- paramnum = tcmd->paramnum; /* have it at easy access */
-
- switch (tcmd->type)
- {
- case TC_EXEC: /* executable command */
- case TC_MISC: /* misc setting command */
- if (tcmd->func != NULLVFP)
- (*tcmd->func)(tnc2,p);
-
- return;
-
- case TC_ON_OFF: /* On/Off switch */
- if ((word = getword(&p)) == NULLCHAR)
- showparm(tnc2,tcmd,0); /* show value */
- else {
- if (word[0] == 'Y' || (word[0] == 'O' && word[1] == 'N'))
- v = 1;
- else
- if (word[0] == 'N' || (word[0] == 'O' && word[1] == 'F'))
- v = 0;
- else {
- tnc2_mesg(tnc2,tnc2_bad);
- return;
- }
-
- showparm(tnc2,tcmd,1); /* show old value */
- tnc2->param[paramnum] = v; /* set new */
- tnc2_flow(tnc2,2 - tnc2->param[72]); /* flowctrl based on XFLOW */
- }
-
- return;
-
- case TC_DECVAL: /* decimal value */
- case TC_HEXVAL: /* hexadecimal value */
- if ((word = getword(&p)) == NULLCHAR)
- showparm(tnc2,tcmd,0); /* show value */
- else {
- showparm(tnc2,tcmd,1); /* show old value */
-
- if (*word == '$') /* new in HEX? */
- tnc2->param[paramnum] = htoi(++word);
- else
- tnc2->param[paramnum] = atoi(word);
- }
-
- return;
-
- case TC_TEXT: /* a text */
- if (p != NULLCHAR) {
- while (*p == ' ' || *p == '\t') /* skip whitespace */
- p++;
-
- if (*p == '\0' || *p == '\r')
- p = NULLCHAR;
- }
-
- if (p == NULLCHAR)
- showparm(tnc2,tcmd,0); /* show value */
- else {
- showparm(tnc2,tcmd,1); /* show old value */
-
- if (tnc2->text[paramnum] != NULLCHAR)
- free(tnc2->text[paramnum]);
-
- if ((p[0] == '%' || p[0] == '&') &&
- (p[1] == '\0' || p[1] == '\r'))
- tnc2->text[paramnum] = NULLCHAR;
- else
- if ((tnc2->text[paramnum] = malloc(strlen(p) + 1)) != NULLCHAR)
- strcpy(tnc2->text[paramnum],p);
- }
- return;
-
- case TC_TIMER: /* Every/After timer */
- if ((word = getword(&p)) == NULLCHAR)
- showparm(tnc2,tcmd,0); /* show value */
- else {
- if (word[0] == 'E')
- v = 1;
- else
- if (word[0] == 'A')
- v = 0;
- else {
- tnc2_mesg(tnc2,tnc2_bad);
- return;
- }
-
- if ((word = getword(&p)) == NULLCHAR) {
- tnc2_mesg(tnc2,tnc2_notenough);
- return;
- }
-
- showparm(tnc2,tcmd,1); /* show old value */
- tnc2->every[paramnum] = v; /* set new */
- stop_timer(&tnc2->timer[paramnum]);
- if ((tnc2->timer[paramnum].start = MS2TICK((long) tcmd->func) * atoi(word)) != 0)
- start_timer(&tnc2->timer[paramnum]);
- }
-
- return;
- }
- }
-
- tcmd++; /* try to match next cmd */
- }
-
- eh:
- tnc2_mesg(tnc2,"?EH\r"); /* command not found */
- }
-
- /* send any data present in the linebuffer */
- static void
- tnc2_send (tnc2)
- register struct tnc *tnc2;
-
- {
- switch (tnc2->mode)
- {
- case TM_CMD:
- return; /* command mode, don't send */
-
- case TM_TRANS: /* trans mode, add cmdchars */
- if (tnc2->passc) { /* buffered cmdchars? */
- if (run_timer(&tnc2->timer[2])) { /* still timing? */
- start_timer(&tnc2->timer[1]); /* then restart PACTIME */
- return; /* and try again later */
- }
- while (tnc2->passc) {
- tnc2->linebuf[tnc2->linepos++] = tnc2->param[18]; /* add them */
- tnc2->passc--;
- }
- }
- break;
- }
-
- if (tnc2->linepos != 0) {
- if (tnc2->axp != NULLAX25) /* connection? */
- sendp_ax25(tnc2->axp,qdata(tnc2->linebuf,tnc2->linepos),
- PID_FIRST|PID_LAST|PID_NO_L3);
- else
- if (tnc2->param[78]) /* TXUIFRAM */
- sendui_ax25(tnc2->interface,&tnc2->unproto,
- qdata(tnc2->linebuf,tnc2->linepos),
- PID_FIRST|PID_LAST|PID_NO_L3);
-
- tnc2->linepos = 0; /* clear the buffer */
- }
-
- if (tnc2->every[1] && /* PACTIME EVERY ... */
- !run_timer(&tnc2->timer[1]) &&
- (tnc2->mode == TM_TRANS || tnc2->param[15])) /* TRANS or CPACTIME */
- start_timer(&tnc2->timer[1]);
- }
-
- /* go to command mode */
- static void tnc2_cmd (tnc2)
- register struct tnc *tnc2;
-
- {
- tnc2_flow(tnc2,2 - tnc2->param[72]); /* flowctrl based on XFLOW */
- tnc2_mesg(tnc2,tnc2_cr);
- tnc2_mesg(tnc2,tnc2_prompt);
- tnc2->mode = TM_CMD;
- tnc2->linepos = 0;
- tnc2->timer[2].func = NULLVFP; /* no CMDTIME func */
- tnc2->passc = 0;
- }
-
- /* this routine gets called by main() each loop, to process incoming data */
- /* for the emulated TNC2 */
- void
- tnc2_serv (tnc2)
- register struct tnc *tnc2;
-
- {
- int c;
- struct mbuf *bp,*slip_decode();
- char gotcha = 0;
-
- /* check if we should block input (packet queue too long) if not, */
- /* read characters from client and process them */
-
- while ((tnc2->mode == TM_CMD || tnc2->axp == NULLAX25 || len_q(tnc2->axp->txq) <= tnc2->axp->maxframe) &&
- (c = tnc2_ichar(tnc2)) >= 0)
- {
- switch (tnc2->mode)
- {
- case TM_CMD: /* command mode */
- if (c == TCH_BREAK) /* a BREAK received? */
- break; /* ignore it */
-
- switch (tnc2_line(tnc2,c & 0x7f)) /* edit an input line */
- {
- case TL_COMPLETE: /* done entering command */
- tnc2_exec(tnc2); /* execute command */
- tnc2->linepos = 0; /* clear the buffer */
- if (tnc2->mode != TM_CMD) /* changed mode? */
- break;
-
- case TL_CANCEL: /* cancelled */
- tnc2_mesg(tnc2,tnc2_prompt); /* new prompt */
- break;
- }
- break;
-
- case TM_CONV: /* converse mode */
- if (c == TCH_BREAK) /* a BREAK received? */
- c = tnc2->param[18]; /* make command-mode escape */
-
- if (!tnc2->param[0]) /* 8BITCONV OFF? */
- c &= ~0x80; /* strip high bit */
-
- switch (tnc2_line(tnc2,c)) /* edit an input line */
- {
- case TL_COMPLETE: /* entered a line */
- case TL_PACKET: /* entered a packet */
- tnc2_send(tnc2); /* send it */
- break;
-
- case TL_COMMAND: /* to command mode */
- tnc2_cmd(tnc2);
- break;
- }
- break;
-
- case TM_TRANS: /* transparent mode */
- if (tnc2->param[67] && /* TRFLOW */
- ((tnc2->param[62] && c == tnc2->param[62]) || /* START */
- (tnc2->param[63] && c == tnc2->param[63]))) /* STOP */
- continue; /* ignore them */
-
- if (c == TCH_BREAK) { /* a BREAK? */
- tnc2_cmd(tnc2); /* to command mode */
- break;
- }
-
- if (tnc2->param[18] && /* command char enabled? */
- c == uchar(tnc2->param[18]) && /* command-mode escape? */
- tnc2->passc < 3 && /* less than 3 before? */
- /* check if (within cmdtime && already in sequence) ||
- (after cmdtime && first in sequence) */
- ((run_timer(&tnc2->timer[2]) | gotcha) ^ !tnc2->passc))
- {
- if (++tnc2->passc == 3){ /* 3rd command-mode char? */
- tnc2->timer[2].func = tnc2_cmd; /* goto cmdmode after CMDTIME */
- tnc2->timer[2].arg = (char *) tnc2;
- }
- break;
- }
- else
- {
- while (tnc2->passc) { /* another, add cmdmode chars */
- tnc2->linebuf[tnc2->linepos++] = tnc2->param[18];
- tnc2->passc--;
- }
- tnc2->timer[2].func = NULLVFP;
- }
-
- tnc2->linebuf[tnc2->linepos++] = c;
-
- if (tnc2->linepos >= 256 || tnc2->linepos >= uchar(tnc2->param[51]))
- tnc2_send(tnc2); /* send complete packets */
-
- break;
-
- case TM_KISS: /* KISS mode */
- if (c == TCH_BREAK) /* a BREAK? */
- break; /* ignore it */
-
- if ((bp = slip_decode(&tnc2->slip,c)) != NULLBUF) { /* decode it */
- switch (uchar(pullchar(&bp)))
- {
- case KISS_DATA:
- if (bp != NULLBUF) {
- if(tnc2->interface->forw != NULLIF)
- (*tnc2->interface->forw->raw)(tnc2->interface->forw,bp);
- else
- (*tnc2->interface->raw)(tnc2->interface,bp);
-
- bp = NULLBUF;
- }
- break;
-
- case KISS_SPEC: /* TNC-specific ctrl */
- tnc2->param[77] = pullchar(&bp); /* set KISSRX */
- break;
-
- case KISS_QUIT:
- tnc2->param[76] = 0; /* KISS OFF */
- tnc2->mode = TM_CMD;
- dotnrestart(tnc2);
- tnc2_mesg(tnc2,tnc2_prompt);
- break;
- }
-
- free_p(bp);
- }
- break;
- }
-
- gotcha = 1;
- }
-
- if (tnc2->axp != NULLAX25) /* connection? */
- tnc2_recv(tnc2->axp,0); /* flush receive queue */
-
- if (gotcha) {
- if (tnc2->mode == TM_TRANS) {
- tnc2->timer[2].start = SEC2TICK(uchar(tnc2->param[12])); /* CMDTIME */
- start_timer(&tnc2->timer[2]);
- }
-
- if ((tnc2->linepos != 0 || tnc2->passc != 0) && /* something buffered */
- (tnc2->mode == TM_TRANS ||
- (tnc2->mode == TM_CONV && tnc2->param[15])) && /* CPACTIME */
- (!tnc2->every[1] || !run_timer(&tnc2->timer[1])))
- start_timer(&tnc2->timer[1]); /* start PACTIME timer */
- }
- }
-
- /* find the tnc controlblock for a connection */
- static struct tnc *
- find_tnc (axp)
- register struct ax25_cb *axp;
-
- {
- register struct tnc *tnc2;
- register struct tnc *rv = NULLTNC;
-
- for (tnc2 = tnc2s; tnc2 != NULLTNC; tnc2 = tnc2->next) {
- if (tnc2->interface == axp->interface &&
- tnc2->axcall == (struct ax25_call *) axp->user) {
- if (tnc2->axp == axp)
- return tnc2; /* this one is connected */
-
- if (tnc2->axp == NULLAX25)
- rv = tnc2; /* this one is free */
- }
- }
-
- return rv;
- }
-
- /* state-change upcall handler for TNC2 */
- void
- tnc2_state(axp,old,new,msg)
- register struct ax25_cb *axp;
- int old,new,msg;
-
- {
- register struct tnc *tnc2;
- struct mbuf *bp;
- char tmp[100];
- extern void disc_ax25();
-
- switch (new) /* check new status */
- {
- case CONNECTED:
- if ((tnc2 = find_tnc(axp)) == NULLTNC) {
- axp->state = DISCONNECTED; /* refuse it, send DM */
-
- /* send *** connect request to TNC's that could accept the connect */
- for (tnc2 = tnc2s; tnc2 != NULLTNC; tnc2 = tnc2->next) {
- if (tnc2->interface == axp->interface &&
- tnc2->axcall == (struct ax25_call *) axp->user &&
- tnc2->mode < TM_TRANS &&
- !tnc2->param[55]) /* BBSMSGS */
- {
- tnc2_mesg(tnc2,tnc2_conrq);
- pdax25(tmp,&axp->addr);
- tnc2_mesg(tnc2,tmp);
- tnc2_mesg(tnc2,tnc2_cr);
- }
- }
-
- return;
- }
-
- if (tnc2->axp == NULLAX25) {
- /* new, incoming connection */
- if (!tnc2->param[21]) { /* CONOK ON? */
- axp->state = DISCONNECTED; /* no, refuse it, send DM */
-
- if (tnc2->mode < TM_TRANS && /* *** connect request when allowed */
- !tnc2->param[55]) { /* BBSMSGS */
- tnc2_mesg(tnc2,tnc2_conrq);
- pdax25(tmp,&axp->addr);
- tnc2_mesg(tnc2,tmp);
- tnc2_mesg(tnc2,tnc2_cr);
- }
-
- return;
- }
-
- tnc2->axp = axp;
- tnc2->status |= TS_DCD; /* set DCD on */
-
- if (tnc2->param[13] && tnc2->text[1] != NULLCHAR) {/* CMSG, CTEXT */
- if ((bp = alloc_mbuf(1)) != NULLBUF) {
- *bp->data = PID_FIRST|PID_LAST|PID_NO_L3;
- bp->cnt = 1;
- bp->next = qstring(tnc2->text[1]);
- enqueue(&axp->txq,bp);
- }
- }
-
- if (tnc2->param[14]) /* CMSGDISC */
- axp->r_upcall = axp->t_upcall = disc_ax25;
- else
- axp->r_upcall = tnc2_recv;
-
- if (tnc2->param[8]) /* CBELL */
- tnc2_ochar(tnc2,'\007');
- }
-
- if (tnc2->mode == TM_CMD && tnc2->linepos == 0 &&
- !tnc2->param[47] && !tnc2->param[46]) /* NOMODE OFF, NEWMODE OFF */
- tnc2->mode = tnc2->conmode;
-
- break;
-
- case DISCONNECTED:
- if ((tnc2 = find_tnc(axp)) == NULLTNC)
- return;
-
- tnc2->axp = NULLAX25;
- break;
- }
-
- if (msg != LAPBNOMS && msg != LAPBDISC &&
- (tnc2->mode < TM_TRANS || msg < LAPBRESF)) {
- sprintf(tmp,"*** %s: ",ax25mesgs[msg]);
- tnc2_mesg(tnc2,tmp);
- pdax25(tmp,&axp->addr);
- tnc2_mesg(tnc2,tmp);
-
- if (msg == LAPBCONN && tnc2->param[22]){ /* CONSTAMP */
- time_t tloc;
-
- time(&tloc);
- sprintf(tmp," [%s]",tnc2_daytime(tnc2,tloc));
- tnc2_mesg(tnc2,tmp);
- }
- tnc2_mesg(tnc2,tnc2_cr);
- }
-
- if (new == DISCONNECTED) {
- tnc2_mesg(tnc2,"*** DISCONNECTED\r");
-
- tnc2->status &= ~TS_DCD; /* DCD off */
-
- if (tnc2->mode != TM_CMD &&
- !tnc2->param[47] && tnc2->param[46]){ /* NOMODE OFF, NEWMODE ON */
- tnc2->mode = TM_CMD;
- tnc2->linepos = 0;
- tnc2_flow(tnc2,2 - tnc2->param[72]); /* flowctrl based on XFLOW */
- tnc2_mesg(tnc2,tnc2_prompt);
- }
- }
- }
-
- /* receive upcall handler for TNC2 */
- static void
- tnc2_recv (axp,cnt)
- struct ax25_cb *axp;
- int16 cnt;
-
- {
- register struct tnc *tnc2;
- struct mbuf *bp,*recv_ax25();
- unsigned char c;
-
- if (axp->rxq == NULLBUF) /* nothing queued, */
- return; /* nothing to do */
-
- if ((tnc2 = find_tnc(axp)) == NULLTNC) {
- disc_ax25(axp);
- return;
- }
-
- switch (tnc2->mode)
- {
- case TM_CMD: /* command mode */
- return;
-
- case TM_CONV: /* converse */
- if (tnc2->param[29] && tnc2->linepos != 0) /* FLOW ON */
- return;
-
- case TM_TRANS: /* transparent */
- if (!tnc2_ochar(tnc2,-1)) /* test for blocked queue */
- return;
-
- if (tnc2->param[59] && (cnt == 0 || cnt > 255))
- cnt = 255; /* upper limit for RXBLOCK fmt */
-
- if ((bp = recv_ax25(axp,cnt)) == NULLBUF)
- return;
-
- if (tnc2->param[59]) { /* RXBLOCK */
- tnc2_ochar(tnc2,0xff);
- cnt = len_mbuf(bp); /* bytes in received packet */
- tnc2_ochar(tnc2,0xf0 | (cnt >> 4));
- tnc2_ochar(tnc2,0xf0 | cnt);
- tnc2_ochar(tnc2,PID_FIRST|PID_LAST|PID_NO_L3);
- }
-
- while (pullup(&bp,&c,1) == 1) {
- if (!tnc2_ochar(tnc2,c))
- break;
-
- if (c == '\r' && tnc2->mode == TM_CONV && tnc2->param[2]) /* AUTOLF */
- if (!tnc2_ochar(tnc2,'\n'))
- break;
- }
-
- free_p(bp);
- break;
- }
-
- #ifdef BEACON
- if (!tnc2->every[0]) /* BEACON AFTER */
- start_timer(&tnc2->timer[0]);
- #endif
- }
-
- /* handle incoming packets in KISS mode */
- /* when a TNC2 on this interface is in KISS mode, the packet is duplicated */
- /* and sent to the client. return value is 0 if no TNC found in KISS mode */
- int
- tnc2_kissrcv (interface,hdr,bp,kissrx)
- struct interface *interface;
- struct ax25 *hdr;
- struct mbuf *bp;
- int kissrx;
-
- {
- register struct tnc *tnc2;
- struct mbuf *hbp,*dbp,*htonax25(),*slip_encode();
- int rv = 0;
- unsigned char c;
-
- for (tnc2 = tnc2s; tnc2 != NULLTNC; tnc2 = tnc2->next) {
- if (tnc2->interface == interface && tnc2->mode == TM_KISS) {
- /* only receive packets at or above KISSRX level */
- if (tnc2->param[77] >= kissrx) { /* KISSRX */
- if (tnc2_ochar(tnc2,-1) && /* test for blocked queue */
- dup_p(&dbp,bp,0,(unsigned int) MAXINT16) != 0) {
- if ((hbp = htonax25(hdr,dbp)) != NULLBUF) {
- /* Put type field for KISS TNC on front */
- if ((dbp = pushdown(hbp,1)) != NULLBUF) {
- hbp = NULLBUF;
- dbp->data[0] = KISS_DATA;
- dbp = slip_encode(dbp);
- while (pullup(&dbp,&c,1) == 1)
- if (!tnc2_ochar(tnc2,c))
- break;
- }
- }
-
- /* when out of memory or fifo full, free everything */
- free_p(dbp);
- free_p(hbp);
- }
- }
-
- rv = 1;
- }
- }
-
- return rv;
- }
-
- #ifdef BEACON
- /* send a beacon (arghh!!) */
- static void
- tnc2_beacon (tnc2)
- register struct tnc *tnc2;
-
- {
- struct ax25 beacon;
-
- if (tnc2->text[0] != NULLCHAR) { /* BTEXT */
- memcpy(&beacon,&tnc2->unproto,sizeof(struct ax25));
- setcall(&beacon.dest,"BEACON"); /* send it to BEACON */
-
- sendui_ax25(tnc2->interface,&beacon,qstring(tnc2->text[0]),
- PID_FIRST|PID_LAST|PID_NO_L3);
- }
-
- if (tnc2->every[0]) /* BEACON EVERY */
- start_timer(&tnc2->timer[0]);
- }
- #endif
-
- static void
- dotnconmode (tnc2,args)
- struct tnc *tnc2;
- char *args;
-
- {
- char *word;
-
- tnc2_mesg(tnc2,"CONMODE ");
- if ((word = getword(&args)) != NULLCHAR)
- tnc2_mesg(tnc2,tnc2_was);
-
- tnc2_mesg(tnc2,(tnc2->conmode == TM_CONV)? "CONVERSE\r" : "TRANS\r");
-
- if (word != NULLCHAR)
- tnc2->conmode = (*word != 'T')? TM_CONV : TM_TRANS;
- }
-
- /* get callsign and digi string from commandline */
- static int
- tnc2_path (tnc2,addr,args)
- register struct tnc *tnc2;
- register struct ax25 *addr; /* where to store it */
- char **args; /* ptr to command tail ptr */
-
- {
- register char *word;
-
- if ((word = getword(args)) == NULLCHAR)
- return 1; /* nothing, return 1 */
-
- memset(addr,0,sizeof(*addr));
-
- if(setcall(&addr->dest,word) < 0){
- tnc2_mesg(tnc2,tnc2_call);
- return -1;
- }
-
- ASSIGN(addr->source,tnc2->axcall->addr); /* Set sourcecall = our own call */
-
- if ((word = getword(args)) != NULLCHAR) { /* Set digipeater path */
- if (strncmp(word,"VIA",strlen(word))) {
- tnc2_mesg(tnc2,"?VIA\r");
- return -1;
- }
-
- while ((word = getword(args)) != NULLCHAR) {
- if (++(addr->ndigis) > MAXDIGIS){
- tnc2_mesg(tnc2,tnc2_toomany);
- return -1;
- }
-
- if(setcall(&addr->digis[addr->ndigis - 1],word) < 0){
- tnc2_mesg(tnc2,tnc2_call);
- return -1;
- }
- }
- }
-
- return 0; /* all ok, return 0 */
- }
-
- static void
- dotnconnect (tnc2,args)
- struct tnc *tnc2;
- char *args;
-
- {
- struct ax25 addr;
- struct ax25_cb *open_ax25();
- int rv;
- extern int16 axwindow;
-
- if ((rv = tnc2_path(tnc2,&addr,&args)) < 0)
- return;
-
- if (rv != 0 || tnc2->axp != NULLAX25) {
- dotncstatus(tnc2);
- return;
- }
-
- if ((tnc2->axp = open_ax25(&addr,axwindow,tnc2_recv,NULLFP,tnc2_state,
- tnc2->interface,(char *) tnc2->axcall)) == NULLAX25) {
- tnc2_mesg(tnc2,"*** FAILED\r");
- return;
- }
-
- if (!tnc2->param[47] && tnc2->param[46]) /* NOMODE OFF, NEWMODE ON */
- if ((tnc2->mode = tnc2->conmode) == TM_TRANS)
- dotntrans(tnc2);
- }
-
- static void
- dotnconverse (tnc2)
- struct tnc *tnc2;
-
- {
- tnc2_flow(tnc2,2 - tnc2->param[72]); /* flowctrl based on XFLOW */
- tnc2->mode = TM_CONV;
- }
-
- static void
- dotncstatus (tnc2)
- register struct tnc *tnc2;
-
- {
- int state;
- char tmp[100];
-
- tnc2_mesg(tnc2,"Link state is: ");
-
- if (tnc2->axp == NULLAX25)
- state = DISCONNECTED;
- else
- state = tnc2->axp->state;
-
- switch (state)
- {
- case DISCONNECTED:
- tnc2_mesg(tnc2,"DISCONNECTED");
- break;
-
- case SETUP:
- tnc2_mesg(tnc2,"CONNECT in progress");
- break;
-
- case CONNECTED:
- tnc2_mesg(tnc2,"CONNECTED to ");
- pdax25(tmp,&tnc2->axp->addr);
- tnc2_mesg(tnc2,tmp);
- break;
-
- case DISCPENDING:
- tnc2_mesg(tnc2,"DISCONNECT in progress");
- break;
-
- case FRAMEREJECT:
- tnc2_mesg(tnc2,"FRMR in progress");
- break;
- }
-
- tnc2_mesg(tnc2,tnc2_cr);
- }
-
- static void
- dotndaytime (tnc2,args)
- struct tnc *tnc2;
- char *args;
-
- {
- time_t tloc;
-
- if (getword(&args) != NULLCHAR) /* attempt to set clock */
- return; /* ignore it */
-
- time(&tloc); /* read current time */
- tnc2_mesg(tnc2,tnc2_daytime(tnc2,tloc)); /* show current time */
- tnc2_mesg(tnc2,tnc2_cr);
- }
-
- static void
- dotndiscon (tnc2)
- struct tnc *tnc2;
-
- {
- if (tnc2->axp == NULLAX25)
- dotncstatus(tnc2);
- else
- disc_ax25(tnc2->axp);
- }
-
- static void
- dotndisplay (tnc2)
- struct tnc *tnc2;
-
- {
- register struct tnccommand *tcmd;
-
- for (tcmd = tnccommands; tcmd->name[0] != '\0'; tcmd++)
- if (tcmd->type != TC_EXEC)
- showparm(tnc2,tcmd,0);
- else
- if (tcmd->func == dotnmycall)
- dotnmycall(tnc2);
- }
-
- static void
- dotnmycall (tnc2)
- struct tnc *tnc2;
-
- {
- char buf[10];
-
- tnc2_mesg(tnc2,"MYCALL ");
- pax25(buf,&tnc2->axcall->addr);
- tnc2_mesg(tnc2,buf);
- tnc2_mesg(tnc2,tnc2_cr);
- }
-
- void dotnreset (tnc2)
- struct tnc *tnc2;
-
- {
- int i;
-
- for (i = 0; i < TNCTIMERS; i++) /* stop timers */
- stop_timer(&tnc2->timer[i]);
-
- tnc2->conmode = TM_CONV; /* CONMODE CONVERSE */
- memcpy(tnc2->param,def_params,sizeof(tnc2->param));
- for (i = 0; i < TNCTEXTS; i++) { /* all texts empty */
- if (tnc2->text[i] != NULLCHAR)
- free(tnc2->text[i]);
- tnc2->text[i] = NULLCHAR;
- }
- tnc2->timer[0].start = 0; /* BEACON EVERY 0 */
- #ifdef BEACON
- tnc2->timer[0].func = tnc2_beacon;
- tnc2->timer[0].arg = (char *) tnc2;
- #endif
- tnc2->every[0] = 1;
- tnc2->timer[1].start = SEC2TICK(1); /* PACTIME AFTER 10 */
- tnc2->timer[1].func = tnc2_send;
- tnc2->timer[1].arg = (char *) tnc2;
- tnc2->every[1] = 0;
- memset(&tnc2->unproto,0,sizeof(tnc2->unproto));
- setcall(&tnc2->unproto.dest,"QST"); /* UNPROTO QST */
- ASSIGN(tnc2->unproto.source,tnc2->axcall->addr);
-
- dotnrestart(tnc2);
- }
-
- static void dotnrestart (tnc2)
- struct tnc *tnc2;
-
- {
- int i;
- extern char version[];
-
- for (i = 0; i < TNCTIMERS; i++) /* stop timers */
- stop_timer(&tnc2->timer[i]);
-
- if (tnc2->axp != NULLAX25) {
- del_ax25(tnc2->axp);
- tnc2->axp = NULLAX25;
- }
-
- if (tnc2->param[76]) { /* KISS */
- tnc2_flow(tnc2,0); /* no flowctrl at all */
- tnc2->mode = TM_KISS;
-
- tnc2_mesg(tnc2,"[KISS]\300"); /* a hint for the user */
- return;
- }
-
- tnc2_flow(tnc2,2 - tnc2->param[72]); /* flowctrl based on XFLOW */
-
- tnc2_mesg(tnc2,"\r\rAX.25 TNC2 emulator in KA9Q NET\rWritten by R.E. Janssen, PE1CHL\rRelease ");
- tnc2_mesg(tnc2,version);
- tnc2_mesg(tnc2,"\rInterface: ");
- tnc2_mesg(tnc2,tnc2->interface->name);
- tnc2_mesg(tnc2,tnc2_cr);
- }
-
- static void
- dotntrans (tnc2)
- struct tnc *tnc2;
-
- {
- tnc2_flow(tnc2,2 - (tnc2->param[70] & tnc2->param[72])); /* TXFLOW and XFLOW */
- tnc2->mode = TM_TRANS;
- }
-
- static void
- dotnunproto (tnc2,args)
- struct tnc *tnc2;
- char *args;
-
- {
- struct ax25 addr;
- int rv;
- char buf[100];
-
- if ((rv = tnc2_path(tnc2,&addr,&args)) < 0)
- return;
-
- tnc2_mesg(tnc2,"UNPROTO ");
- if (!rv)
- tnc2_mesg(tnc2,tnc2_was);
-
- pdax25(buf,&tnc2->unproto);
- tnc2_mesg(tnc2,buf);
- tnc2_mesg(tnc2,tnc2_cr);
-
- if (!rv)
- memcpy(&tnc2->unproto,&addr,sizeof(addr));
- }
-